﻿#include "delegate.h"
#include <QDebug>
#include <QSpinBox>
#include <QDateEdit>
#include <QCheckBox>
#include <QComboBox>
#include <QDateTimeEdit>
#include <QDateEdit>
#include <QPushButton>
#include <QLineEdit>
#include <QCalendarWidget>
#include <QProgressBar>
#include <QApplication>
#include <QPainter>
#include <QMouseEvent>
#include <QTableView>
Delegate::Delegate(QObject *parent): QStyledItemDelegate(parent)
{
    this->init();
}

QWidget *Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/*option*/, const QModelIndex &/*index*/) const
{
    if(delegateType == "QCheckBox")
        return 0;
    /*创建编辑器*/
    QWidget *editor = new QWidget(parent);

    /*判断具体的委托，并将编辑器进行响应的设置*/
    if(delegateType == "QSpinBox")
    {
        //必须加上parent，负责QSpinBox显示在视图外面
        QSpinBox *sbox = new QSpinBox(parent);
        sbox->setRange(sboxMinValue,sboxMaxValue);
        sbox->setSuffix(sboxSuffixStr);
        sbox->setPrefix(sboxPrefixStr);
        sbox->setSingleStep(sboxSingleStep);
        sbox->setStepType(sboxStepType);
        sbox->setValue(sboxInitValue);
        editor = sbox;
        connect(sbox,SIGNAL(valueChanged(int)),this,SLOT(on_valueChanged(int)));
    }
    else if(delegateType == "QComboBox")
    {
        QComboBox *cbox = new QComboBox(parent);
        cbox->addItems(cboxItems);
        cbox->setEditable(cboxEditable);
        editor = cbox;

    }
    else if (delegateType == "QDateTimeEdit") {
        QDateTimeEdit *dateTime = new QDateTimeEdit(parent);
        dateTime->setCalendarPopup(true);
        dateTime->setDisplayFormat("yyyy-MM-dd HH:mm:ss");
        dateTime->calendarWidget()->setLocale(QLocale::Chinese);
        editor = dateTime;
    }
    else if (delegateType == "QDateEdit") {
        QDateEdit *date = new QDateEdit(parent);
        date->setCalendarPopup(true);
        date->setDisplayFormat("yyyy-MM-dd");
        date->calendarWidget()->setLocale(QLocale::Chinese);
        editor = date;
    }
    else if (delegateType == "QTimeEdit") {
        QTimeEdit *time = new QTimeEdit(parent);
        time->setDisplayFormat("HH:mm:ss");
        editor = time;
    }
    else if (delegateType == "QLineEdit")
    {
        QLineEdit *lineEidt = new QLineEdit(parent);
        lineEidt->setEchoMode(delegatePwd ? QLineEdit::Password : QLineEdit::Normal);
        editor = lineEidt;
        connect(lineEidt, SIGNAL(textChanged(QString)), this, SIGNAL(valueChanged(QString)));
    }

    return editor;
}

void Delegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    auto value = index.model()->data(index, Qt::EditRole);
    if(delegateType == "QSpinBox")
    {
        QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
        spinBox->setValue(value.toInt());
    }
    else if(delegateType == "QComboBox")
    {
        QComboBox *cbox = static_cast<QComboBox*>(editor);
        cbox->setCurrentText(value.toString());
    }
    else if (delegateType == "QDateTimeEdit")
    {
        QDateTimeEdit *dateTime = static_cast<QDateTimeEdit *>(editor);
        dateTime->setDateTime(QDateTime::fromString(value.toString(), "yyyy-MM-dd HH:mm:ss"));
    }
    else if (delegateType == "QDateEdit")
    {
        QDateEdit *date = static_cast<QDateEdit *>(editor);
        date->setDate(QDate::fromString(value.toString(), "yyyy-MM-dd"));
    }
    else if (delegateType == "QTimeEdit")
    {
        QTimeEdit *time = static_cast<QTimeEdit *>(editor);
        time->setTime(QTime::fromString(value.toString(), "HH:mm:ss"));
    }
    else if (delegateType == "QLineEdit")
    {
        QLineEdit *lineEidt = static_cast<QLineEdit *>(editor);
        lineEidt->setText(value.toString());
    }
    else
    {
        QStyledItemDelegate::setEditorData(editor, index);
    }


}

void Delegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                            const QModelIndex &index) const
{
    QVariant value = model->data(index);
    if(delegateType == "QSpinBox")
    {
        QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
        value = spinBox->value();
    }
    else if(delegateType == "QComboBox")
    {
        QComboBox *cbox = static_cast<QComboBox*>(editor);
        value = cbox->currentText();
    }
    else if (delegateType == "QDateTimeEdit")
    {
        QDateTimeEdit *dateTime = static_cast<QDateTimeEdit *>(editor);
        value = dateTime->dateTime().toString("yyyy-MM-dd HH:mm:ss");
    }
    else if (delegateType == "QDateEdit")
    {
        QDateEdit *date = static_cast<QDateEdit *>(editor);
        value = date->date().toString("yyyy-MM-dd");
    }
    else if (delegateType == "QTimeEdit")
    {
        QTimeEdit *time = static_cast<QTimeEdit *>(editor);
        value = time->time().toString("HH:mm:ss");
    }
    else if (delegateType == "QLineEdit")
    {
        QLineEdit *lineEidt = static_cast<QLineEdit *>(editor);
        value = lineEidt->text();
    }
    model->setData(index, value, Qt::EditRole);

}

void Delegate::updateEditorGeometry(QWidget *editor,
                                    const QStyleOptionViewItem &option,
                                    const QModelIndex &/* index */) const
{
    editor->setGeometry(option.rect);
}

void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{

    if(index.column() == delegateColumnID)
    {
        if(delegateType == "QProgressBar")
        {
            drawProgressBar(painter,option,index);
        }
        else if(delegateType == "QCheckBox")
        {
            drawCheckBox(painter,option,index);
        }
        else if(delegateType == "QPushButton")
        {
            drawPushButton(painter,option,index);
        }
        else if(delegateType == "QPixmap" && judgmentColumn>=0)
        {
            drawPixmap(painter,option,index);
        }
        else if (delegateType == "QLineEdit" && delegatePwd)
        {
            drawLineEdit(painter, option, index);
        }

    }//if
    else
    {
        QStyledItemDelegate::paint(painter,option,index);
    }
}

bool Delegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    //Qt6中如果调用了 qApp->setStyleSheet 设置了全局样式的话,鼠标移动也会触发 editorEvent TNND
    if (event->type() == QEvent::MouseMove) {
        return false;
    }

    //处理编辑数据
    QString data = index.data(Qt::DisplayRole).toString();
    if (delegateType == "QCheckBox") {
        //鼠标松开不用处理,不然会重复设置
        if (event->type() == QEvent::MouseButtonRelease) {
            return false;
        }

        //如果当前的文字和设置的选中文字一致则说明是选中
        checkedText = (data == checkBoxChecked ? checkBoxUnchecked : checkBoxChecked);
        model->setData(index, checkedText, Qt::EditRole);
        emit valueChanged(checkedText);
    } else if (delegateType == "QPushButton") {
        QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
        mousePoint = mouseEvent->pos();
        mousePressed = false;

        //没有按钮对应的值则不处理
        QStringList list = data.split("|");
        int count = list.count();
        if (data.isEmpty() || count == 0) {
            return false;
        }

        //根据按钮数量自动计算按钮对应的区域
        int x = option.rect.x();
        int y = option.rect.y();
        int width = option.rect.width() / count;
        int height = option.rect.height();

        QList<QRect> btnRect;
        for (int i = 0; i < count; ++i) {
            btnRect << QRect(x + i * width, y, width, height);
        }

        if (event->type() == QEvent::MouseButtonPress) {
            //鼠标按下更新对应按钮区域是否按下,并判断按下的区域是哪个按钮,发送对应的按钮索引和index
            for (int i = 0; i < count; ++i) {
                if (btnRect.at(i).contains(mousePoint)) {
                    mousePressed = true;
                    emit buttonClicked(i, index);
                    break;
                }
            }
        }

        //需要返回真表示需要继续绘制
        return true;
    }

    //和事件过滤器类似,也需要继续返回执行
    return QStyledItemDelegate::editorEvent(event, model, option, index);
}
void Delegate::init()
{
    delegateType = "QSpinBox";
    delegateColumnID = -1;

    sboxMaxValue = 100;
    sboxMinValue = 0;

    sboxPrefixStr = "";
    sboxSuffixStr = "";

    sboxSingleStep = 1;
    sboxInitValue = 0;

    sboxStepType = QAbstractSpinBox::DefaultStepType;

    cboxItems.clear();
    cboxEditable = true;

    checkBoxChecked = "true";
    checkBoxUnchecked = "false";

    pgbarMax = 100;
    pgbarMin = 0;
    pgbarAlignment = Qt::AlignCenter;
    isTextVisible = true;
    invertedAppearance = false;
    
    imgOk = QPixmap(":/corr.png");
    imgNo = QPixmap(":/erro.png");
    imgWidth = 20;
    imgHeigth = 20;
    judgmentColumn = -1;
    judgmentValue = "错误";
    judgmentCondition = "contains";
}

void Delegate::checkData(const QString &data,bool *selse)const
{
    if (judgmentCondition == "==") {
        if (data == judgmentValue) {
            *selse = true;
        }
    } else if (judgmentCondition == ">") {
        if (data.toDouble() > judgmentValue.toDouble()) {

            *selse = true;
        }
    } else if (judgmentCondition == ">=") {
        if (data.toDouble() >= judgmentValue.toDouble()) {
            *selse = true;
        }
    } else if (judgmentCondition == "<") {
        if (data.toDouble() < judgmentValue.toDouble()) {
            *selse = true;
        }
    } else if (judgmentCondition == "<=") {
        if (data.toDouble() <= judgmentValue.toDouble()) {
            *selse = true;
        }
    } else if (judgmentCondition == "!=") {
        if (data != judgmentValue) {
            *selse = true;
        }
    } else if (judgmentCondition == "contains") {
        QStringList list = judgmentValue.split("|");
        foreach (QString value, list) {
            if (data.contains(value)) {
                *selse = true;
                break;
            }
        }
    }
}

void Delegate::drawProgressBar(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index)const
{
    //获得视图中的值
    int value = index.model()->data(index,Qt::DisplayRole).toInt();
    //创建包含QProgressBar样式信息类
    QStyleOptionProgressBar soPgbar;
    //使用我们创建的pgBar初始化soPgbar
    soPgbar.initFrom(pgBar);
    //设置最大值和最小值
    soPgbar.maximum = pgbarMax;
    soPgbar.minimum = pgbarMin;
    //设置进度条值
    soPgbar.progress = value;
    //设置状态
    soPgbar.state |= QStyle::State_Enabled;
    soPgbar.state |= QStyle::State_Horizontal;
    //设置位置和大小
    soPgbar.rect = option.rect;
    //设置文本
    soPgbar.text = QString("%1%").arg(value);
    //设置文本是否可见
    soPgbar.textVisible = isTextVisible;
    //设置文本居中
    soPgbar.textAlignment = pgbarAlignment;
    //设置进度条的进度方向
    soPgbar.invertedAppearance = invertedAppearance;
    //绘制
    QApplication::style()->drawControl(QStyle::CE_ProgressBar,&soPgbar,painter,pgBar);
}

void Delegate::drawCheckBox(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    //处理复选框委托,判断是否选中,设置选中状态
    QString data = index.data(Qt::EditRole).toString();
    bool checked = (data == checkBoxChecked);
    QStyleOptionButton styleOption;
    styleOption.initFrom(checkBox);
    styleOption.state = checked ? QStyle::State_On : QStyle::State_Off;
    styleOption.state |= QStyle::State_Enabled;

    //设置居中正方形区域
    int width = option.rect.width();
    int height = option.rect.height();
    int size = qMin(width, height);
    int x = option.rect.center().x() - (size / 4);
    int y = option.rect.y();
    styleOption.rect = QRect(x, y, size, size);

    QApplication::style()->drawControl(QStyle::CE_CheckBox, &styleOption, painter, checkBox);
}

void Delegate::drawPushButton(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    //没有按钮对应的值则不处理
    QString data = index.data(Qt::DisplayRole).toString();

    QStringList list = data.split("|");
    int count = list.count();
    if (data.isEmpty() || count == 0) {
        return;
    }

    //处理按钮集合委托,自动计算分配宽度
    int x = option.rect.x();
    int y = option.rect.y();
    int width = option.rect.width() / count;
    int height = option.rect.height();

    //分别绘制按钮集合
    for (int i = 0; i < count; ++i) {
        QStyleOptionButton styleOption;
        styleOption.initFrom(button);

        styleOption.rect = QRect(x + i * width, y, width, height);
        styleOption.text = list.at(i);
        styleOption.state |= QStyle::State_Enabled;

        //鼠标按下更新对应的样式
        if (mousePressed) {
            if (styleOption.rect.contains(mousePoint)) {
                styleOption.state |= QStyle::State_Sunken;
            }
        }


        //第四个参数也可以为空,为空的话就不能应用样式表
        QApplication::style()->drawControl(QStyle::CE_PushButton, &styleOption, painter, button);

    }
}

void Delegate::drawPixmap(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QString data = index.model()->index(index.row(),judgmentColumn).data().toString();
    bool selse;
    checkData(data,&selse);

    //图标自动缩放到指定大小
    QPixmap pixmap = (selse?imgOk:imgNo);
    pixmap = pixmap.scaled(QSize(imgWidth, imgHeigth), Qt::KeepAspectRatio, Qt::SmoothTransformation);
    QApplication::style()->drawItemPixmap(painter, option.rect, Qt::AlignCenter, pixmap);
}

void Delegate::drawLineEdit(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    //统计数量，转换成对应数量的密码样式
    QString value = index.model()->data(index, Qt::DisplayRole).toString();
    int len = value.length();
    QString text;
    for (int i = 0; i < len; ++i)
    {
        text += "●";
    }

    QRect rect = option.rect;
    rect.setX(rect.x() + 2);
    painter->drawText(rect, Qt::AlignCenter, text);
}

void Delegate::on_valueChanged(int value)
{
    emit valueChanged(QString("%1").arg(value));
}

void Delegate::setDelegateType(const QString &delegateType)
{
    this->delegateType = delegateType;
    /*将需要使用paint绘制的控件在这里new出来。
     *为什么不在paint函数中new呢？
     * 因为不能在const成员函数paint中分配非静态数据成员
   */
    if(delegateType == "QProgressBar")
    {
        pgBar = new QProgressBar;
    }
    else if(delegateType == "QPushButton")
    {
        button = new QPushButton;
    }
    else if (delegateType == "QCheckBox")
    {
        checkBox = new QCheckBox;
    }

}

void Delegate::setDelegateColumn(const int delegateColumnID)
{
    this->delegateColumnID = delegateColumnID;
}

void Delegate::setSboxMaxValue(const int max)
{
    sboxMaxValue = max;
}

void Delegate::setSboxMinValue(const int min)
{
    sboxMinValue = min;
}

void Delegate::setSboxPrefixStr(const QString &prefix)
{
    sboxPrefixStr = prefix;
}

void Delegate::setSboxSuffixStr(const QString &suffix)
{
    sboxSuffixStr = suffix;
}
void Delegate::setSboxSingleStep(const int SingleStep)
{
    sboxSingleStep = SingleStep;
}

void Delegate::setSboxInitValue(const int initValue)
{
    sboxInitValue = initValue;
}
void Delegate::setSboxStepType(QAbstractSpinBox::StepType st)
{
    sboxStepType = st;
}

void Delegate::setCboxItems(const QStringList &items)
{
    cboxItems = items;
}

void Delegate::setCboxEditable(bool editable)
{
    cboxEditable = editable;
}

void Delegate::setPgBarRange(const int min, const int max)
{
    pgbarMin = min;
    pgbarMax = max;
}

void Delegate::setPgBarTextVisible(bool isTextVisible)
{
    this->isTextVisible = isTextVisible;
}

void Delegate::setPgBarAlignment(Qt::Alignment pgbarAlignment)
{

    this->pgbarAlignment = pgbarAlignment;
}

void Delegate::setInvertedAppearance(bool invertedAppearance)
{
    this->invertedAppearance = invertedAppearance;
}

void Delegate::setCheckBoxText(const QString &checkBoxChecked, const QString &checkBoxUnchecked)
{
    this->checkBoxChecked = checkBoxChecked;
    this->checkBoxUnchecked = checkBoxUnchecked;
}

void Delegate::setImgOk(const QPixmap &imgOk)
{
    this->imgOk = imgOk;
}

void Delegate::setImgNo(const QPixmap &imgNo)
{
    this->imgNo = imgNo;
}

void Delegate::setImgSize(int width,int heigth)
{
    this->imgWidth = width;
    this->imgHeigth = heigth;
}

void Delegate::setJudgmentColumn(int column)
{
    this->judgmentColumn = column;
}

void Delegate::setJudgmentValue(const QString &value)
{
    this->judgmentValue = value;
}

void Delegate::setJudgmentCondition(const QString &condition)
{
    this->judgmentCondition = condition;
}

void Delegate::setDelegatePwd(bool showDelegatePwd)
{
    this->delegatePwd = showDelegatePwd;
}

void Delegate::setComboBox(QAbstractItemView *view, QAbstractItemModel *model)
{
    for (int row = 0; row < model->rowCount(); ++row) {
        QComboBox *comboBox = new QComboBox();
        comboBox->addItems(cboxItems);
        view->setIndexWidget(model->index(row, delegateColumnID), comboBox);
    }
}

